package com.soulless.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * <pre>
 * 反射
 *
 * 相关的主要类
 * - java.lang.Class：代表一个类， Class对象表示某个类加载后在堆中的对象
 * - java.lang.reflec.Method：代表类的方法，Method对象表示某个类的方法
 * - java.lang.reflect.Field：代表类的成员变量，Field对象表示，某个类的成员变量
 * - java.lang.reflect.Constructor：代表类的构造方法，Constructor对象表示构造器
 * </pre>
 *
 * @author zenglei
 * @date 2022/04/21/ 09:07
 */
public class ReflectDemo {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, InstantiationException {
        /**
         * 反射获取class的方式
         */

        /**
         * 根据类获取
         */
        Class<?> cls1 = Apple.class;

        /**
         * 根据类型路径获取
         * 会报 ClassNotFoundException
         */
        Class<?> cls2 = Class.forName("com.soulless.reflect.Apple");

        /**
         * 此方式基本不用
         */
        Apple apple = new Apple();
        Class<? extends Apple> cls3 = apple.getClass();

        /**
         * 其他方式
         */
        ClassLoader cl = apple.getClass().getClassLoader();
        Class<?> cls4 = cl.loadClass("com.soulless.reflect.Apple");

        /**
         * 基本数据类型
         */
        Class<Integer> intCls = int.class;

        /**
         * 包装类型
         */
        Class<Integer> integerCls = Integer.TYPE;

        /**
         * 获取类成员
         * 会报 NoSuchFieldException
         * 设置字段值会报 IllegalAccessException
         * getField 只能获取public的，包括从父类继承来的字段。
         * getDeclaredField 可以获取本类所有的字段，包括private的，但是不能获取继承来的字段。 (注： 这里只能获取到private的字段，但并不能访问该private字段的值,除非加上setAccessible(true))
         */
        Object obj = cls1.newInstance();
        Field[] fields = cls1.getFields();
//        Field colorField = cls1.getField("color");
        Field colorField = cls1.getDeclaredField("color");
        /**
         * 私有成员需要设置 accessible
         */
        colorField.setAccessible(true);
        colorField.set(obj, "123");

        /**
         * 获取类方法
         * 会报 NoSuchMethodException
         * 调用方法会报 InvocationTargetException
         * newInstance() 会报 InstantiationException
         */
        Method[] methods = cls1.getMethods();
        Method setColor = cls1.getMethod("setColor", String.class);
//        setColor.invoke(obj, new Object[] {"123123"});
        Method getColorMethod = cls1.getMethod("getColor");
        Object invoke = getColorMethod.invoke(obj, new Object[]{});
        System.out.println(invoke);
    }

}


class Apple {

    /**
     * 颜色
     */
    private String color;

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}